#include "Col.ph"
#ifdef __GNUG__
#pragma implementation
#endif

#include "String.h"
#include "Error.h"
#include "ET_stdio.h"
	
#ifdef macintosh
	extern "C" memmove(void*, const void*, size_t);
#else
	extern "C" void bcopy(const void*, void*, size_t);
#endif

void *MemCpy(void *to, const void *from, register size_t length)
{
#ifdef macintosh
	memmove(to, from, length);
#else
	bcopy(from, to, length);
#endif
	return to;
}

int StuffChar(const char *src, char *dst, int dstlen, char* specchars, char stuffchar)
{
	register const char *p;
	register char *q, *end= dst+dstlen-1;

	for (p= src, q= dst; *p && q < end; ) {
		if (strchr(specchars, *p)) {
			*q++= stuffchar;
			if (q < end)
				*q++= *p++;
		} else
			*q++= *p++;
	}
	*q= '\0';

	if (*p != 0)
		return -1;
	return q-dst;
}

char *strsave(const char *s, int l)
{
	if (s == 0 || l == 0)
		return 0;
	if (l < 0)
		l= strlen(s);
	char *dst= new char[l+1];
    strncpy(dst, s, l);
    dst[l]= '\0';
	return dst;
}

char *strreplace(char **s, const char *r, int l)
{
	if (s == 0)
		Fatal("strreplace", "s == 0, replace: %s l: %d", r, l);
	if (r == 0 || l == 0)
		return *s;
	if (l < 0)
		l= strlen(r);
	//fprintf(stderr, "old: %s new: %s l:%d\n", *s ? "(null)" : *s, r, l);
	*s= (char*) Storage::ReAlloc(*s, l+1);
	strncpy(*s, r, l);
	(*s)[l]= '\0';
	return *s;
}

char *strvreplace(char **s, const char *fmt, va_list ap)
{
	char buf[2000];

	if (s == 0)
		Fatal("strvreplace", "s == 0, fmt: %s", fmt);
	if (fmt == 0)
		return *s;

	vsprintf(buf, fmt, ap);

	*s= (char*) Storage::ReAlloc(*s, strlen(buf)+1);
	return strcpy(*s, buf);
}

char *strfreplace(char **s, const char *va_(fmt), ...)
{
	va_list ap;
	char buf[2000];

	va_start(ap,va_(fmt));
	if (s == 0)
		Fatal("strfreplace", "s == 0, fmt: %s", va_(fmt));
	if (va_(fmt) == 0)
		return *s;
	vsprintf(buf, va_(fmt), ap);
	va_end(ap);
	*s= (char*) Storage::ReAlloc(*s, strlen(buf)+1);
	return strcpy(*s, buf);
}

char *strprintf(const char *va_(fmt), ...)
{
	va_list ap;
	char buf[2000];

	va_start(ap,va_(fmt));
	vsprintf(buf, va_(fmt), ap);
	va_end(ap);
	return strsave(buf);
}

char *strvprintf(const char *fmt, va_list ap)
{
	char buf[2000];
	vsprintf(buf, fmt, ap);
	return strsave(buf);
}

bool strismember(const char *va_(cp), ...)
{
	char *s;
	va_list ap;
	bool found= FALSE;
	va_start(ap,va_(cp));
	for (int i= 0; s= va_arg(ap, char*); i++)
		if (strcmp(va_(cp), s) == 0) {
			found= TRUE;
			break;
		}
	va_end(ap);
	return found;
}

char *strn0cpy(char *dst, const char *src, int l)
{
	strncpy(dst, src, l-1);
	dst[l-1]= '\0';
	return dst;
}

u_long strhash(const char *str)
{
	register u_long h= 0, g;
	register const byte *p= (const byte*)str;

	while (*p) {
		h= (h << 4) + *p++;
		if (g= (h & 0xf0000000))
			h= (h ^ (g >> 24)) ^ g;
	}
	return h;
}

char *strquotechar(byte ch, char *q)
{
	switch(ch) {
	case '\n':
		*q++='\\'; *q++='n';
		break;
	case '\r':
		*q++='\\'; *q++='r';
		break;
	case '\0':
		*q++='\\'; *q++='0';
		break;
	case '\t':
		*q++='\\'; *q++='t';
		break;
	case '\v':
		*q++='\\'; *q++='v';
		break;
	case '\f':
		*q++='\\'; *q++='f';
		break;
	case '\b':
		*q++='\\'; *q++='b';
		break;
	default:
		if (Isascii(ch) && Isprint(ch)) {
			*q++= ch;
		} else {
			*q++= '\\';
			*q++= 'x';
			*q++= hexChars[ch/16];
			*q++= hexChars[ch%16];
		}
	}
	return q;
}

const char *BaseName(const char *name)
{
	if (name) {
		if (name[0] == '/' && name[1] == '\0')
			return name;
		char *cp;
		if (cp= strrchr(name, '/'))
			return ++cp;
		return name;
	}
	return "Error in String::BaseName";
}

int StrCmp(register const byte *s1, register const byte *s2, int n,
												register const byte *map)
{
	if (s1 == 0 || s2 == 0)
		return -1;
	if (map) {
		if (n < 0) {
			while (map[*s1] == map[*s2++])
				if (map[*s1++] == '\0')
					return 0;
			return map[*s1] - map[*--s2];
		} else {
			while (--n >= 0 && map[*s1] == map[*s2++])
				if (map[*s1++] == '\0')
					return 0;
			return (n < 0) ? 0 : map[*s1] - map[*--s2];
		}
	} else {
		if (n < 0) {
			while (*s1 == *s2++)
				if (*s1++ == '\0')
					return 0;
			return (int)*s1 - (int)*--s2;
		} else {
			while (--n >= 0 && *s1 == *s2++)
				if (*s1++ == '\0')
					return 0;
			return (n < 0) ? 0 : (int)*s1 - (int)*--s2;
		}
	}
}

static const int
	cb_size= 4096,
	fld_size= 2048;

// a circular formating buffer
static char     formbuf[cb_size];       // some slob for form overflow
static char     *bfree= formbuf;
static char     *endbuf= &formbuf[cb_size-1];

char *form(const char* va_(fmt), ...)
{
	va_list ap;
	va_start(ap,va_(fmt));
	char *format= (char*) va_(fmt);
	register char *buf= bfree;

	if (buf+fld_size > endbuf)
		buf= formbuf;

	vsprintf(buf, format, ap);
	int l= strlen(buf);
	if (l > fld_size)
		Fatal("form", "buffer overflow");
	bfree= buf+l+1;
	va_end(ap);
	return buf;
}

